///@file ElasticMaterial.cpp
///@brief Implementation of the class representing a linear elastic material
///@author Arnaud Duval
///@version 0.0
///@date 2010/02/26

#include "ElasticMaterial.h"

///@brief Default constructor
ElasticMaterial::ElasticMaterial()
{
	young = 0;
	poisson = 0;
}

///@brief Destructor
ElasticMaterial::~ElasticMaterial()
{

}

///@brief Constructor with arguments
///@param Dyoung given Young modulus
///@param Dpoisson given Poisson ratio
ElasticMaterial::ElasticMaterial(double Dyoung, double Dpoisson)
{
	young = Dyoung;
	poisson = Dpoisson;
}

///@brief Set the value of a given parameter
///@param idx Index of parameter to set (1 for Young modulus, 2 for Poisson ratio)
///@param value Value to set to parameter
void ElasticMaterial::SetParameter(int idx, double value)
{
	assert((idx == 1)||(idx == 2));
	switch(idx)
	{
		case 1:
		{
			young = value;
		}break;
		case 2:
		{
			poisson = value;
		}break;
	}	
}

///@brief Compute stess tensor increment from strain tensor tensor increment and initial stress and strain
///@param Eini Strain tensor at the beginning of increment
///@param Sini Stress tensor at the beginning of increment
///@param DE Strain increment
StressTensor ElasticMaterial::Dstress(StrainTensor Eini, StressTensor Sini, StrainTensor DE)
{
	StressTensor res;
	double lambda = (poisson*young)/((1.+poisson)*(1. - 2.*poisson));
	double mu = young/(2.*(1. + poisson));
	SymTensor2 delta(3,'k');

	res &= (lambda*(DE.Trace()*delta) + (SymTensor2)(2.*(mu*DE)));

	return res;
}

///@brief Print output
///@param s out stream
void ElasticMaterial::PrintOutput(std::ostream &s)
{
	s << reference.c_str() << "\t" << "Elastic\tE = " << young << "\tnu = " << poisson;
}

///@brief Similar to an Abaqus UMAT
///@warning The name of this function should be changed
///@return true if convergence is OK
///@param strain Strain at the beginning of increment
///@param dstrain Increment of strain
///@param stress Stress at the beginning of increment. Should be updated
///@param ddsdde Tangent operator at the end of increment
bool ElasticMaterial::UMAT(const Vector& strain, const Vector& dstrain, Vector& stress, Matrix& ddsdde)
{
    ///@warning only the 2D plane stress case is taken into account
    if(strain.Dim() == 3)
    {
        ddsdde(1,1) = 1.;
        ddsdde(1,2) = poisson;
        ddsdde(1,3) = 0.;
        ddsdde(2,1) = poisson;
        ddsdde(2,2) = 1.;
        ddsdde(2,3) = 0.;
        ddsdde(3,1) = 0.;
        ddsdde(3,2) = 0.;
        ddsdde(3,3) = (1. - poisson)/2.;
        ddsdde = ddsdde*young/((1. -poisson)*(1. - poisson));

        stress = stress + (ddsdde | dstrain);
    }

    
    return true;
}